package cn.lingyangwl.agile.dynamic.config.core;

import cn.lingyangwl.agile.dynamic.config.core.event.*;
import cn.lingyangwl.agile.dynamic.config.model.*;
import cn.lingyangwl.agile.dynamic.config.remote.*;
import cn.lingyangwl.agile.model.constants.*;
import cn.lingyangwl.agile.model.enums.*;
import cn.lingyangwl.agile.model.module.config.*;
import cn.lingyangwl.agile.model.utils.*;
import cn.lingyangwl.agile.tenant.core.utils.*;
import cn.lingyangwl.framework.core.utils.spring.*;
import cn.lingyangwl.framework.tool.core.exception.*;
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 配置工厂
 * @author shenguangyang
 */
@Slf4j
@Component
public class ConfigFactory {

    /**
     * key: tenant_id:config_key
     */
    private static final Map<String, ConfigInfo> configMap = new ConcurrentHashMap<>();

    @Resource
    @Lazy
    private ConfigManageApi configManageApi;

    @Resource
    private ScanConfigListener scanConfigListener;

    @PostConstruct
    public void init() {

    }

    public void deleteConfig(ConfigMsg req) {
        ConfigKeyEnum configKey = ConfigKeyEnum.ofAndCheck(req.getConfigKey());
        ConfigDefineEnum configDefine = ConfigDefineEnum.ofByKey(configKey);
        String cacheKey = ConfigUtils.getCacheKey(configDefine);
        synchronized (cacheKey.intern()) {
            configMap.remove(cacheKey);
            log.info("删除配置数据, cacheKey: {}", cacheKey);
            scanConfigListener.execListener(req);
            SpringUtils.getContext().publishEvent(new ConfigDeleteEvent(configKey.getKey()));
        }
    }

    public boolean hasConfig(ConfigDefineEnum configDefine) {
        return configMap.containsKey(ConfigUtils.getCacheKey(configDefine));
    }

    public ConfigInfo getConfigOfNonNull(ConfigDefineEnum configDefine) {
        return getConfig(configDefine, true);
    }

    public ConfigInfo getConfig(ConfigDefineEnum configDefine) {
        return getConfig(configDefine, false);
    }

    private ConfigInfo getConfig(ConfigDefineEnum configDefine, boolean requestNonNull) {
        String cacheKey = ConfigUtils.getCacheKey(configDefine);
        initPublicConfig();

        String tenantId = ConfigUtils.getTargetTenantId(configDefine);

        return TenantUtils.execute(DataIsolateLevel.ALL, tenantId, () -> {
            ConfigInfo configInfo = configMap.get(cacheKey);
            if (Objects.isNull(configInfo)) {
                synchronized (cacheKey.intern()) {
                    configInfo = configMap.get(cacheKey);
                    if (Objects.nonNull(configInfo)) {
                        return configInfo;
                    }
                    String errorMsg = String.format("尚未配置 【%s】参数, 请到配置中心进行设置", configDefine.getName());
                    try {
                        configInfo = configManageApi.getUseConfig(configDefine).get();
                    } catch (Exception e) {
                        throw new BizException("获取配置失败");
                    }
                    log.warn("初始化租户 {} 的 {} 配置, config: {}", tenantId, configDefine.name(), JSON.toJSONString(configInfo));
                    if (Objects.isNull(configInfo)) {
                        log.error("tenantId: {}, error: {}", tenantId, errorMsg);
                        if (requestNonNull) {
                            throw new BizException(errorMsg);
                        }
                        return null;
                    }
                    configMap.put(cacheKey, configInfo);
                }
            }
            return configInfo;
        });
    }

    /**
     * 初始化公共配置
     */
    private void initPublicConfig() {
        String cacheKey = ConfigUtils.getCacheKey(ConfigDefineEnum.WEB_SITE);
        ConfigInfo configInfo = configMap.get(cacheKey);
        if (Objects.isNull(configInfo)) {
            synchronized (cacheKey.intern()) {
                configInfo = configMap.get(cacheKey);
                if (Objects.nonNull(configInfo)) {
                    return;
                }
                try {
                    configInfo = configManageApi.getUseConfig(ConfigDefineEnum.WEB_SITE).get();
                    if (Objects.isNull(configInfo)) {
                        log.error("配置不存在, cacheKey: {}", cacheKey);
                        throw new BizException("公共配置不存在");
                    }
                } catch (Exception e) {
                    if (e instanceof BizException) {
                        throw (BizException) e;
                    }
                    log.error("error: ", e);
                    throw new BizException("获取公共配置失败");
                }
                configMap.put(cacheKey, configInfo);
            }
        }
    }
}
